package com.weai.portal.service.impl;

import com.google.gson.Gson;
import com.weai.config.DeepSeekConfig;
import com.weai.portal.entity.TaskReport;
import com.weai.portal.service.TaskReportAIService;
import com.weai.portal.util.WeeklyReportPrompt;
import com.weai.service.AIModelService;
import dev.langchain4j.model.chat.ChatLanguageModel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class TaskReportAIServiceImpl implements TaskReportAIService {

    private final ChatLanguageModel chatModel;
    private final DeepSeekConfig deepSeekConfig;
    private final AIModelService aiModelService;
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter YEAR_MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyy年MM月");
    private static final DateTimeFormatter MONTH_DAY_FORMATTER = DateTimeFormatter.ofPattern("MM月dd日");
    
    // 设置最大项目数量限制，避免提示词过长
    private static final int MAX_PROJECTS_PER_BATCH = 1000;
    
    // 重试延迟（毫秒）
    private static final long[] RETRY_DELAYS = {1000, 3000, 5000, 10000};

    @Override
    public String analyzeTask(TaskReport taskReport) {
        try {
            // 构建提示词
            String prompt = String.format("""
                    你是一个专业的项目分析师，请根据以下项目信息进行客观分析：
                    
                    【项目基本信息】
                    - 项目名称：%s
                    - 当前状态：%s
                    - 原计划工作：%s
                    - 实际进展：%s
                    - 存在问题：%s
                    
                    【分析要求】
                    1. 评估进度是否符合预期（超预期/符合预期/未达预期）
                    2. 基于原计划、实际进展和问题，简明扼要地总结项目情况
                    
                    【输出格式】
                    仅返回以下JSON格式结果，不要有任何其他解释或前后缀：
                    {
                      "progressRating": "[超预期/符合预期/未达预期]",
                      "progressSummary": "[50字以内的项目进展总结]"
                    }""",
                    taskReport.getTitle(),
                    getStatusText(taskReport.getStatus()),
                    taskReport.getOriginalPlan(),
                    taskReport.getActualProgress(),
                    taskReport.getProblems()
            );

            return aiModelService.chat(prompt, 3);
        } catch (Exception e) {
            log.error("分析任务时发生错误: {}", taskReport.getTitle(), e);
            return "{\"isNewProject\":\"是\",\"progressRating\":\"未达预期\",\"progressSummary\":\"无法获取AI分析结果，请查看原因，谢谢配合\"}";
        }
    }
    
    @Override
    public String generateWeeklyReportHtml(List<TaskReport> taskReports) {
        if (taskReports.isEmpty()) {
            return "<p>当前周期没有任务报告数据</p>";
        }
        
        // 基本统计信息
        LocalDate periodStartDate = taskReports.get(0).getPeriodStartDate();
        LocalDate periodEndDate = taskReports.get(0).getPeriodEndDate();
        String yearMonth = periodStartDate != null ? 
                periodStartDate.format(YEAR_MONTH_FORMATTER) : 
                LocalDate.now().format(YEAR_MONTH_FORMATTER);
        
        String weekRange = "";
        if (periodStartDate != null && periodEndDate != null) {
            weekRange = periodStartDate.format(MONTH_DAY_FORMATTER) + "-" + 
                      periodEndDate.format(MONTH_DAY_FORMATTER);
        }
        
        // 统计项目进展情况
        long todoCount = taskReports.stream().filter(r -> "todo".equals(r.getStatus())).count();
        long inProgressCount = taskReports.stream().filter(r -> "inProgress".equals(r.getStatus())).count();
        long doneCount = taskReports.stream().filter(r -> "done".equals(r.getStatus())).count();
        
        try {
            // 构建进展顺利的项目数据
            String progressProjectsData = buildProgressProjectsData(taskReports);
            // 构建问题和风险点汇总数据
            String problemProjectsData = buildProblemProjectsData(taskReports);
            
            // 限制项目数量，避免提示词过长，为后面先留足空间
            List<TaskReport> limitedReports = taskReports;
            if (taskReports.size() > MAX_PROJECTS_PER_BATCH) {
                log.warn("项目数量{}超过限制{}，将进行截取", taskReports.size(), MAX_PROJECTS_PER_BATCH);
                limitedReports = taskReports.subList(0, MAX_PROJECTS_PER_BATCH);
            }

            // 准备业务类项目明细数据
            List<Map<String, String>> businessProjects = prepareBusinessProjects(limitedReports);
            // 准备科技类项目明细数据
            List<Map<String, String>> techProjects = prepareTechProjects(limitedReports);
            
            // 生成提示词
            String prompt = WeeklyReportPrompt.buildPrompt(
                    yearMonth,
                    weekRange,
                    taskReports.size(),
                    todoCount,
                    inProgressCount,
                    doneCount,
                    progressProjectsData,
                    problemProjectsData,
                    businessProjects,
                    techProjects
            );
            
            log.info("生成周报HTML提示词，长度: {}", prompt.length());
            log.info("生成周报HTML提示词: \n {}", prompt);
            
            // 调用大模型，带重试
            String htmlContent = callModelWithRetry(prompt, 5);
            log.info("大模型返回的HTML长度: {}", htmlContent.length());
            
            // 检查输出是否可能被截断
            if (!htmlContent.contains("</body>") || !htmlContent.contains("</html>")) {
                log.warn("大模型输出可能被截断，HTML标签不完整");
            }
            
            // 清理HTML内容
            htmlContent = cleanHtmlContent(htmlContent);
            
            return htmlContent;
        } catch (Exception e) {
            log.error("生成HTML周报失败", e);
            // 如果失败，返回一个简单的错误HTML
            return generateErrorHtml(periodStartDate, periodEndDate, taskReports.size());
        }
    }
    
    /**
     * 构建进展顺利项目数据，筛选progressRating为"超预期"或"符合预期"的记录
     * @param taskReports 所有任务报告
     * @return 格式化的进展顺利项目数据
     */
    private String buildProgressProjectsData(List<TaskReport> taskReports) {
        StringBuilder progressData = new StringBuilder();
        
        // 筛选进展顺利的项目(超预期或符合预期)
        List<TaskReport> goodProgressProjects = taskReports.stream()
                .filter(r -> {
                    String rating = r.getProgressRating();
                    return rating != null && (rating.contains("超预期") || rating.contains("符合预期"));
                })
                .sorted(Comparator.comparing(r -> r.getProgressRating().contains("超预期") ? 0 : 1))
                .collect(Collectors.toList());
        
        if (goodProgressProjects.isEmpty()) {
            return "本周没有进展顺利的项目";
        }
        
        // 构建数据，按照项目类型分组
        Map<String, List<TaskReport>> typeGroups = goodProgressProjects.stream()
                .collect(Collectors.groupingBy(
                        r -> r.getType() != null ? r.getType() : "其他项目"
                ));
        
        for (Map.Entry<String, List<TaskReport>> entry : typeGroups.entrySet()) {
            String type = entry.getKey();
            List<TaskReport> projects = entry.getValue();
            
            progressData.append("<strong>【").append(type).append("】</strong>\n");
            
            for (TaskReport project : projects) {
                String ratingEmoji = project.getProgressRating().contains("超预期") ? "🌟 " : "✓ ";
                progressData.append("- ").append(ratingEmoji).append(" ")
                        .append("<strong>").append(limitLength(project.getTitle(), 40)).append("</strong>：")
                        .append(project.getProgressSummary())
                        .append("\n");
            }
            progressData.append("\n");
        }
        
        return progressData.toString();
    }
    
    /**
     * 构建主要问题与风险数据，提取所有记录的problems字段与未达预期的项目进行总结
     * @param taskReports 所有任务报告
     * @return 格式化的问题项目数据
     */
    private String buildProblemProjectsData(List<TaskReport> taskReports) {
        // 收集所有有意义的问题
        List<String> allProblems = new ArrayList<>();
        
        // 1. 收集有明确问题的项目
        taskReports.stream()
                .filter(r -> r.getProblems() != null && !r.getProblems().trim().isEmpty())
                .forEach(project -> {
                    String problemContext = String.format("存在的问题: %s",
                            project.getProblems().trim());
                    allProblems.add(problemContext);
                });

        // 检查是否有问题数据
        if (allProblems.isEmpty()) {
            return "本周项目运行顺利，未发现明显风险";
        }
        
        // 记录问题数量
        log.info("收集到{}个问题描述，将交给大模型进行总结", allProblems.size());
        
        // 调用大模型总结问题要点
        try {
            return summarizeProblems(allProblems);
        } catch (Exception e) {
            log.error("大模型总结问题失败", e);
            
            // 如果调用大模型失败，使用原始问题列表
            StringBuilder problemsData = new StringBuilder();
            problemsData.append("**主要问题与风险:**\n\n");
            
            for (String problem : allProblems) {
                problemsData.append("- ").append(problem).append("\n");
            }
            
            return problemsData.toString();
        }
    }
    
    /**
     * 使用大模型总结问题要点
     * @param problemList 问题列表
     * @return 总结后的问题要点
     */
    private String summarizeProblems(List<String> problemList) {
        // 构建问题列表文本
        StringBuilder problemsText = new StringBuilder();
        for (String problem : problemList) {
            problemsText.append("- ").append(problem).append("\n");
        }
        
        // 构建提示词
        String prompt = String.format("""
                请总结以下项目问题，提炼出主要风险点，并按重要性排序:
                
                %s
                
                请以markdown格式返回，要求：
                1. 使用"主要问题与风险"作为标题
                2. 风险点提取清晰，有重点
                3. 每个风险点用无序列表"-"表示
                4. 合并相似问题，归纳共性风险
                5. 保持客观专业的语言风格
                """, problemsText.toString());

        log.info("大模型总结问题，问题列表：\n{}", problemList);
        // 调用大模型API
        String response = aiModelService.chat(prompt, 3);
        log.info("大模型总结问题结果：\n{}", response);
        return response;
    }


    /**
     * 从字符串中提取中文名字，并用“、”拼接
     * @param input 输入字符串
     * @return 拼接后的中文名字
     */
    private String extractChineseNames(String input) {
        if (input == null || input.isEmpty()) {
            return "";
        }
        // 使用正则表达式匹配中文字符
        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("[\u4e00-\u9fa5]+");
        java.util.regex.Matcher matcher = pattern.matcher(input);
        java.util.List<String> names = new java.util.ArrayList<>();
        while (matcher.find()) {
            names.add(matcher.group());
        }
        return String.join("、", names);
    }

    /**
     * 准备业务需求项目数据
     * @param taskReports 所有任务报告
     * @return 业务需求项目的数据列表
     */
    private List<Map<String, String>> prepareBusinessProjects(List<TaskReport> taskReports) {
        List<Map<String, String>> businessProjects = new ArrayList<>();
        
        // 筛选业务需求项目
        List<TaskReport> filteredProjects = taskReports.stream()
                .filter(r -> "业务需求".equals(r.getType()))
                .collect(Collectors.toList());
        
        for (TaskReport project : filteredProjects) {
            Map<String, String> projectData = new HashMap<>();
            projectData.put("subType", project.getSubType() != null ? project.getSubType() : "未分类");
            projectData.put("title", project.getTitle() != null ? project.getTitle() : "未命名项目");
            
            // 状态标记
            String statusMark = switch (project.getStatus()) {
                case "done" -> "[已完成] ";
                case "inProgress" -> "[进行中] ";
                case "todo" -> "[待办] ";
                default -> "";
            };
            
            // 整合实际进展和问题
//            StringBuilder progress = new StringBuilder(statusMark);
            StringBuilder progress = new StringBuilder();
            if (project.getActualProgress() != null && !project.getActualProgress().isEmpty()) {
                progress.append("\n当前进展：\n");
                progress.append(project.getActualProgress());
            }
            
            if (project.getProblems() != null && !project.getProblems().isEmpty()) {
                progress.append("\n存在问题：\n");
                progress.append(project.getProblems());
            }
            
            projectData.put("progress", progress.toString());
            projectData.put("summary", project.getProgressSummary() != null ? project.getProgressSummary() : "");
            projectData.put("rating", project.getProgressRating() != null ? project.getProgressRating() : "");
            projectData.put("busidepart", project.getBusiDepartment() != null ? project.getBusiDepartment() : "");
            projectData.put("busigoal", project.getBusiGoal() != null ? project.getBusiGoal() : "");
            projectData.put("itdepart", project.getItDepartment() != null ? project.getItDepartment() : "");
            projectData.put("receiver",project.getReceiver() != null ? extractChineseNames(project.getReceiver()) : "");

            businessProjects.add(projectData);
        }
        
        return businessProjects;
    }
    
    /**
     * 准备科技专项项目数据
     * @param taskReports 所有任务报告
     * @return 科技专项项目的数据列表
     */
    private List<Map<String, String>> prepareTechProjects(List<TaskReport> taskReports) {
        List<Map<String, String>> techProjects = new ArrayList<>();
        
        // 筛选科技专项项目
        List<TaskReport> filteredProjects = taskReports.stream()
                .filter(r -> "科技专项".equals(r.getType()))
                .collect(Collectors.toList());
        
        for (TaskReport project : filteredProjects) {
            Map<String, String> projectData = new HashMap<>();
            projectData.put("subType", project.getSubType() != null ? project.getSubType() : "未分类");
            projectData.put("title", project.getTitle() != null ? project.getTitle() : "未命名项目");
            
            // 状态标记
            String statusMark = switch (project.getStatus()) {
                case "done" -> "[已完成] ";
                case "inProgress" -> "[进行中] ";
                case "todo" -> "[待办] ";
                default -> "";
            };
            
            // 整合实际进展和问题
//            StringBuilder progress = new StringBuilder(statusMark);
            StringBuilder progress = new StringBuilder();
            if (project.getActualProgress() != null && !project.getActualProgress().isEmpty()) {
                progress.append("\n当前进展：\n");
                progress.append(project.getActualProgress());
            }
            
            if (project.getProblems() != null && !project.getProblems().isEmpty()) {
                if (progress.length() > statusMark.length()) {
                    progress.append("\n存在问题：\n");
                }
                progress.append(project.getProblems());
            }
            
            projectData.put("progress", progress.toString());
            projectData.put("summary", project.getProgressSummary() != null ? project.getProgressSummary() : "");
            projectData.put("rating", project.getProgressRating() != null ? project.getProgressRating() : "");
            projectData.put("busidepart", project.getBusiDepartment() != null ? project.getBusiDepartment() : "");
            projectData.put("busigoal", project.getBusiGoal() != null ? project.getBusiGoal() : "");
            projectData.put("itdepart", project.getItDepartment() != null ? project.getItDepartment() : "");
            projectData.put("receiver",project.getReceiver() != null ? extractChineseNames(project.getReceiver()) : "");
            techProjects.add(projectData);
        }
        
        return techProjects;
    }
    
    /**
     * 限制字符串长度
     * @param text 原文本
     * @param maxLength 最大长度
     * @return 限制长度后的文本
     */
    private String limitLength(String text, int maxLength) {
        if (text == null) return "";
        return text.length() > maxLength ? text.substring(0, maxLength) + "..." : text;
    }
    
    /**
     * 带重试机制的模型调用
     * @param prompt 提示词
     * @param maxRetries 最大重试次数
     * @return 模型响应
     */
    private String callModelWithRetry(String prompt, int maxRetries) {
        return aiModelService.chat(prompt, maxRetries);
    }
    
    /**
     * 清理HTML内容
     * @param htmlContent 原始HTML内容
     * @return 清理后的HTML内容
     */
    private String cleanHtmlContent(String htmlContent) {
        if (htmlContent == null || htmlContent.isEmpty()) {
            return "<p>无法生成HTML内容</p>";
        }
        
        // 移除可能的markdown标记，但保留换行符
        htmlContent = htmlContent.replace("```html", "")
                              .replace("```", "")
                              .trim();
        
        // 检查HTML完整性，确保包含基本结构
        boolean hasDoctype = htmlContent.contains("<!DOCTYPE html>");
        boolean hasHtmlOpen = htmlContent.contains("<html");
        boolean hasHtmlClose = htmlContent.contains("</html>");
        boolean hasBodyOpen = htmlContent.contains("<body");
        boolean hasBodyClose = htmlContent.contains("</body>");
        
        log.info("HTML完整性检查: DOCTYPE={}, <html>={}, </html>={}, <body>={}, </body>={}",
                hasDoctype, hasHtmlOpen, hasHtmlClose, hasBodyOpen, hasBodyClose);
        
        StringBuilder builder = new StringBuilder(htmlContent);
        
        // 添加缺失的闭合标签
        if (hasBodyOpen && !hasBodyClose) {
            builder.append("\n</body>");
            log.warn("HTML缺少</body>标签，已自动添加");
        }
        
        if (hasHtmlOpen && !hasHtmlClose) {
            builder.append("\n</html>");
            log.warn("HTML缺少</html>标签，已自动添加");
        }
        
        // 如果完全缺少基本结构，则添加
        if (!hasDoctype) {
            htmlContent = "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<title>AI虚拟架构组周报</title>\n</head>\n<body>\n" + 
                        builder.toString() + 
                        "\n</body>\n</html>";
            log.warn("HTML结构不完整，已添加基本结构");
        } else {
            htmlContent = builder.toString();
        }
        
        return htmlContent;
    }
    
    /**
     * 生成错误HTML
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @param projectCount 项目数量
     * @return 错误HTML
     */
    private String generateErrorHtml(LocalDate startDate, LocalDate endDate, int projectCount) {
        String dateRange = "";
        if (startDate != null && endDate != null) {
            dateRange = startDate.format(DATE_FORMATTER) + " 至 " + endDate.format(DATE_FORMATTER);
        }
        
        return "<!DOCTYPE html>\n" +
               "<html lang=\"zh-CN\">\n" +
               "<head>\n" +
               "    <meta charset=\"UTF-8\">\n" +
               "    <title>AI虚拟架构组周报</title>\n" +
               "    <style>\n" +
               "        body { font-family: Arial, sans-serif; margin: 0; padding: 20px; }\n" +
               "        h1, h2 { color: #1e3d7b; }\n" +
               "        .error { color: #dc2626; padding: 15px; border-left: 4px solid #dc2626; background-color: #fef2f2; }\n" +
               "    </style>\n" +
               "</head>\n" +
               "<body>\n" +
               "    <h1>AI虚拟架构组周报（" + dateRange + "）</h1>\n" +
               "    <div class=\"error\">\n" +
               "        <h2>生成周报时遇到问题</h2>\n" +
               "        <p>很抱歉，在生成本周周报时遇到了问题。请稍后再试。</p>\n" +
               "        <p>本周共有 " + projectCount + " 个项目需要报告。</p>\n" +
               "    </div>\n" +
               "</body>\n" +
               "</html>";
    }
    
    /**
     * 获取状态的中文描述
     * @param status 状态代码
     * @return 中文描述
     */
    private String getStatusText(String status) {
        if (status == null) return "";
        
        return switch (status) {
            case "todo" -> "待办";
            case "inProgress" -> "进行中";
            case "done" -> "已完成";
            default -> status;
        };
    }
}
